package com.neusoft.service.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.neusoft.dto.ApproveRetroactive;
import com.neusoft.dto.ApproveRetroactiveListDTO;
import com.neusoft.dto.RetroactiveDTO;
import com.neusoft.mapper.*;
import com.neusoft.model.AttendRetroactive;
import com.neusoft.model.Attendance;
import com.neusoft.model.Worktype;
import com.neusoft.service.AttendanceService;
import com.neusoft.utils.EmpUtil;
import com.neusoft.utils.ServerResponse;
import com.neusoft.vo.AttendanceVO;
import com.neusoft.vo.RetroactiveVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@Service
@Transactional
public class AttendanceServiceImpl implements AttendanceService {
    @Resource
    private WorktypeMapper workTypeMapper;
    @Resource
    private ApprovalRelateMapper approvalRelateMapper;
    @Resource
    private AttendanceMapper attendanceMapper;
    @Resource
    private AttendRetroactiveMapper attendRetroactiveMapper;
    @Resource
    private EmpMapper empMapper;
    @Resource
    private DeptMapper deptMapper;

    //考勤打卡
    @Override
    public ServerResponse<?> attendanceIn(Integer id, Integer type) {
        Worktype worktype = attendanceMapper.getWorkTypeByUser(id);
        Date date = DateUtil.parse(DateUtil.now(), "yyyy-MM-dd");
        LambdaQueryWrapper<Attendance> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Attendance::getEmpId, id).eq(Attendance::getDate, date);
        Attendance attendance = attendanceMapper.selectOne(queryWrapper);
        if (attendance == null) {
            attendance = new Attendance();
            attendance.setEmpId(id);
            attendance.setDate(date);
            attendance.setWorktypeId(worktype.getId());
            Integer workdayId = attendanceMapper.getWorkDayIdByDate(date);
            if (workdayId == null) {
                return ServerResponse.error("考勤日期 " + DateUtil.format(date, "yyyy-MM-dd") + " 没有对应的工作日历记录,请先设置当天的工作是什么类型后再打卡");
            }
            attendance.setWorkdayId(workdayId);
        }
        if (type == 1) {
            if (attendance.getCheckInTime() != null) {
                return ServerResponse.error("已经打过卡了", 2);
            }
            attendance.setCheckInTime(DateUtil.parse(DateUtil.now(), "yyyy-MM-dd HH:mm:ss"));
            LocalTime now = LocalTime.now();
            LocalTime checkInTime = worktype.getCheckInTime().toInstant().atZone(ZoneId.systemDefault()).toLocalTime();
            if (now.isAfter(checkInTime)) {
                attendance.setStatus((byte) 1); // 1-迟到
            }
        } else {
            if (attendance.getCheckOutTime() != null) {
                Date checkOutTime = attendance.getCheckOutTime();
                Date now = new Date();
                long minutesBetween = DateUtil.between(checkOutTime, now, DateUnit.MINUTE);
                if (minutesBetween < 3) {
                    return ServerResponse.error("两次打卡时间间隔不足3分钟", 4);
                } else {
                    attendance.setCheckOutTime(DateUtil.parse(DateUtil.now(), "yyyy-MM-dd HH:mm:ss"));
                    checkAndUpdateAttendanceStatus(attendance, now, worktype);
                }
            } else {
                if (attendance.getCheckInTime() == null) {
                    return ServerResponse.error("请先打上班卡", 3);
                }
                attendance.setCheckOutTime(DateUtil.parse(DateUtil.now(), "yyyy-MM-dd HH:mm:ss"));
                Date now = new Date();
                checkAndUpdateAttendanceStatus(attendance, now, worktype);
            }
        }
        if (attendance.getId() == null) {
            if (attendanceMapper.insert(attendance) > 0) {
                return ServerResponse.success("考勤记录插入成功", 1);
            } else {
                return ServerResponse.error("考勤记录插入失败", 0);
            }
        } else {
            if (attendanceMapper.updateById(attendance) > 0) {
                return ServerResponse.success("考勤记录更新成功", 1);
            } else {
                return ServerResponse.error("考勤记录更新失败", 0);
            }
        }
    }
    //获取考勤记录
    @Override
    public List<AttendanceVO> getMyRecords(Integer id, Date startDate, Date endDate) {
        LambdaQueryWrapper<Attendance> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Attendance::getEmpId, id).between(Attendance::getDate, startDate, endDate);
        List<Attendance> attendances = attendanceMapper.selectList(queryWrapper);
        if (attendances != null) {
            return attendances.stream().map(attendance -> {
                AttendanceVO attendanceVO = new AttendanceVO();
                attendanceVO.setId(attendance.getId());
                attendanceVO.setEmployeeName(empMapper.selectById(id).getEmpname());
                attendanceVO.setDepartment(deptMapper.selectById(id).getDeptname());
                attendanceVO.setDate(DateUtil.format(attendance.getDate(), "yyyy-MM-dd"));
                attendanceVO.setCheckInTime(DateUtil.format(attendance.getCheckInTime(), "HH:mm:ss"));
                attendanceVO.setCheckOutTime(DateUtil.format(attendance.getCheckOutTime(), "HH:mm:ss"));
                attendanceVO.setStatus(attendance.getStatus());
                return attendanceVO;
            }).collect(Collectors.toList());
        }else {
            return Collections.emptyList();
        }
    }
    //补签
    @Override
    public ServerResponse<?> applyRetroactive(Integer id, RetroactiveDTO retroactiveDTO) {
        //这里只是补签申请，只需要把补签信息插入到数据库中，不需要判断是否迟到早退等
        Date date = retroactiveDTO.getDate();
        String dateStr = DateUtil.format(date, "yyyy-MM-dd");
        LambdaQueryWrapper<Attendance> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Attendance::getEmpId, id).eq(Attendance::getDate, dateStr);
        Attendance attendance = attendanceMapper.selectOne(queryWrapper);
        AttendRetroactive retroactive = new AttendRetroactive();
        retroactive.setEmpId(id);
        retroactive.setAttendanceId(attendance.getId());
        retroactive.setNewCheckInTime(retroactiveDTO.getClockInTime());
        retroactive.setNewCheckOutTime(retroactiveDTO.getClockOutTime());
        retroactive.setReason(retroactiveDTO.getReason());
        retroactive.setApproveEmpId(attendanceMapper.getAttendanceApproverId(id));
        if (attendRetroactiveMapper.insert(retroactive) > 0) {
            return ServerResponse.success("申请成功");
        } else {
            return ServerResponse.error("申请失败");
        }
    }
    //获取补签列表
    @Override
    public IPage<RetroactiveVO> getRetroactiveList(Integer pageNum, Integer pageSize) {
        //TODO,审批人的id
        //不同部门的审批人不同，根据审批人id获取审批人所在部门的所有补签申请
        Integer currentUserId  = (Integer) 10;
        Page<AttendRetroactive> page = new Page<>(pageNum, pageSize);

        // 使用分页查询
        IPage<AttendRetroactive> attendRetroactivePage = attendRetroactiveMapper.selectPage(page,
                new LambdaQueryWrapper<AttendRetroactive>()
                        .eq(AttendRetroactive::getApproveEmpId, currentUserId)
                        .eq(AttendRetroactive::getApproveStatus, 1)
        );
        // 转换为 VO
        IPage<RetroactiveVO> pageInfo = attendRetroactivePage.convert(attendRetroactive -> {
            RetroactiveVO retroactiveVO = new RetroactiveVO();
            retroactiveVO.setId(attendRetroactive.getId());
            retroactiveVO.setEmployeeId(attendRetroactive.getEmpId());
            retroactiveVO.setEmployeeName(attendanceMapper.getEmpNameById(attendRetroactive.getEmpId()));
            retroactiveVO.setDate(DateUtil.format(attendRetroactive.getCreateTime(), "yyyy-MM-dd"));
            retroactiveVO.setClockInTime(DateUtil.format(attendRetroactive.getNewCheckInTime(), "HH:mm:ss"));
            retroactiveVO.setClockOutTime(DateUtil.format(attendRetroactive.getNewCheckOutTime(), "HH:mm:ss"));
            retroactiveVO.setReason(attendRetroactive.getReason());
            retroactiveVO.setStatus(Integer.valueOf(attendRetroactive.getApproveStatus()));
            return retroactiveVO;
        });
        return pageInfo;
    }
    //审批补签
    @Override
    public ServerResponse<?> approveRetroactive(Integer id, Byte status, String reason) {
        AttendRetroactive retroactive = attendRetroactiveMapper.selectOne(new LambdaQueryWrapper<AttendRetroactive>().eq(AttendRetroactive::getApproveEmpId, id));
        if (retroactive == null) {
            return ServerResponse.error("未找到对应的审批记录");
        }
        if (status == 2) {
            retroactive.setApproveStatus((byte) 2); // 2-通过
            Attendance attendance = attendanceMapper.selectById(retroactive.getAttendanceId());
            if (attendance == null) {
                return ServerResponse.error("未找到对应的考勤记录");
            }

            attendance.setCheckInTime(retroactive.getNewCheckInTime());
            attendance.setCheckOutTime(retroactive.getNewCheckOutTime());
            Worktype worktype = workTypeMapper.selectById(attendance.getWorktypeId());
            if (worktype == null) {
                return ServerResponse.error("未找到对应的工作类型记录");
            }
            updateAttendanceStatus(attendance, worktype);
            attendanceMapper.updateById(attendance);

            retroactive.setApproveRemark(reason);
            retroactive.setApproveTime(new Date());
            attendRetroactiveMapper.updateById(retroactive);
            return ServerResponse.success("审批成功");
        } else {
            retroactive.setApproveStatus((byte) 3); // 3-驳回
            retroactive.setApproveRemark(reason);
            retroactive.setApproveTime(new Date());
            attendRetroactiveMapper.updateById(retroactive);
            return ServerResponse.error("审批驳回");
        }
//        //状态2为审批通过，3为审批不通过
//        AttendRetroactive retroactive = attendRetroactiveMapper.selectOne(new LambdaQueryWrapper<AttendRetroactive>().eq(AttendRetroactive::getApproveEmpId, id));
//       retroactive.setApproveStatus(status);
//        retroactive.setApproveTime(new Date());
//        retroactive.setUpdateTime(new Date());
//        retroactive.setApproveRemark(reason);
//        if (attendRetroactiveMapper.updateById(retroactive) > 0) {
//            int n=attendanceMapper.updateAttendanceTime(retroactive.getAttendanceId(), retroactive.getNewCheckInTime(), retroactive.getNewCheckOutTime(), 0);
//            if (n > 0) {
//                return ServerResponse.success("审批成功");
//            } else {
//                return ServerResponse.error("审批失败");
//            }
//        } else {
//            return ServerResponse.error("审批失败");
//        }
    }

    @Override
    public ServerResponse<?> approveRetroactiveList(ApproveRetroactiveListDTO approveRetroactiveListDTO) {
            for (ApproveRetroactive approveRetroactive : approveRetroactiveListDTO.getApproveRetroactiveList()){
                AttendRetroactive retroactive = attendRetroactiveMapper.selectOne(new LambdaQueryWrapper<AttendRetroactive>().eq(AttendRetroactive::getApproveEmpId, approveRetroactive.getId()));
                if (retroactive == null) {
                    return ServerResponse.error("补签申请不存在,id=" + approveRetroactive.getId());
                }
                if (retroactive.getApproveStatus() != 1) {
                    return ServerResponse.error("补签申请已审批,id=" + approveRetroactive.getId());
                }
                if (approveRetroactive.getStatus() == 2) {
                    retroactive.setApproveStatus(Byte.valueOf((byte) 2)); // 2-通过
                    Attendance attendance = attendanceMapper.selectById(retroactive.getAttendanceId());
                    attendance.setCheckInTime(retroactive.getNewCheckInTime());
                    attendance.setCheckOutTime(retroactive.getNewCheckOutTime());
                    Worktype worktype = workTypeMapper.selectById(attendance.getWorktypeId());
                    updateAttendanceStatus(attendance, worktype);
                    attendanceMapper.updateById(attendance);
                } else  {
                    retroactive.setApproveStatus(Byte.valueOf((byte) 3)); // 3-驳回
                }
                retroactive.setApproveRemark(approveRetroactive.getReason());
                retroactive.setApproveTime(new Date());
                attendRetroactiveMapper.updateById(retroactive);
            }
            return ServerResponse.success("审批成功");
    }

    @Override
    public IPage<AttendanceVO> selectRetroactiveList(Integer pageNum, Integer pageSize) {
        Integer currentUserId  = EmpUtil.getLoginEmpId();
        Page<Attendance> page = new Page<>(pageNum, pageSize);
        // 使用分页查询
        IPage<Attendance> attendancePage = attendanceMapper.selectPage(page,
                new LambdaQueryWrapper<Attendance>()
                        .eq(Attendance::getEmpId, currentUserId)
                        .in(Attendance::getStatus, 1, 2, 3, 4)
        );
        // 转换为 VO
        IPage<AttendanceVO> pageInfo = attendancePage.convert(attendance -> {
            AttendanceVO vo = new AttendanceVO();
            vo.setId(attendance.getId());
            vo.setEmployeeName(empMapper.selectById(attendance.getEmpId()).getEmpname());
            vo.setDepartment(deptMapper.selectById(empMapper.selectById(attendance.getEmpId()).getDeptId()).getDeptname());
            vo.setCheckInTime(DateUtil.format(attendance.getCheckInTime(), "HH:mm:ss"));
            vo.setCheckOutTime(DateUtil.format(attendance.getCheckOutTime(), "HH:mm:ss"));
            vo.setDate(DateUtil.format(attendance.getDate(), "yyyy-MM-dd"));
            vo.setStatus(attendance.getStatus());
            return vo;
        });
        return pageInfo;
    }

    //判断是否早退、旷工
    private void checkAndUpdateAttendanceStatus(Attendance attendance, Date now, Worktype worktype) {
        Date checkOutWorkTypeTime = worktype.getCheckOutTime();
        Date checkInTime = attendance.getCheckInTime();
        long minutes = DateUtil.between(checkInTime, now, DateUnit.MINUTE);
        if (minutes < worktype.getOnDutyMin()) {
            attendance.setStatus(Byte.valueOf((byte) 4)); // 4-旷工
        } else if (DateUtil.compare(now, checkOutWorkTypeTime) < 0) {
            attendance.setStatus(Byte.valueOf((byte) 3)); // 3-早退
        } else {
            attendance.setStatus(Byte.valueOf((byte) 0)); // 0-正常
        }
    }

    private void updateAttendanceStatus(Attendance attendance, Worktype workType) {
        Date checkInTime = attendance.getCheckInTime();
        Date checkOutTime = attendance.getCheckOutTime();
        Date workStartTime = workType.getCheckInTime();
        Date workEndTime = workType.getCheckOutTime();
        Integer onDutyMin = workType.getOnDutyMin();
        Integer offDutyMin = workType.getOffDutyMin();

        if (checkInTime == null || checkOutTime == null) {
            attendance.setStatus(Byte.valueOf((byte) 5)); // 5-未打卡或漏打卡
            return;
        }
        // 转换为LocalTime, 只为用于比较时间方便
        LocalTime checkInLocalTime = LocalDateTime.ofInstant(checkInTime.toInstant(), ZoneId.systemDefault()).toLocalTime();
        LocalTime checkOutLocalTime = LocalDateTime.ofInstant(checkOutTime.toInstant(), ZoneId.systemDefault()).toLocalTime();
        LocalTime workStartLocalTime = LocalDateTime.ofInstant(workStartTime.toInstant(), ZoneId.systemDefault()).toLocalTime();
        LocalTime workEndLocalTime = LocalDateTime.ofInstant(workEndTime.toInstant(), ZoneId.systemDefault()).toLocalTime();
        boolean isLate = checkInLocalTime.isAfter(workStartLocalTime);
        boolean isEarly = checkOutLocalTime.isBefore(workEndLocalTime);
        int workedMinutes = (int) Duration.between(checkInLocalTime, checkOutLocalTime).toMinutes();
        if (isLate) {
            attendance.setStatus(Byte.valueOf((byte) 1)); // 1-迟到
        } else if (isEarly) {
            attendance.setStatus(Byte.valueOf((byte) 2)); // 2-早退
        } else if (workedMinutes < onDutyMin) {
            attendance.setStatus(Byte.valueOf((byte) 3)); // 3-旷工
        } else if (workedMinutes > offDutyMin) {
            attendance.setStatus(Byte.valueOf((byte) 4)); // 4-加班
        } else {
            attendance.setStatus(Byte.valueOf((byte) 0)); // 0-正常
        }
    }

}
